package lz.controls.data
{

	import flash.events.EventDispatcher;
	import lz.controls.events.DataChangeEvent;
	import lz.controls.events.DataChangeType;
	/**
	 * DataProvider 类提供一些方法和属性，这些方法和属性允许您查询和修改任何基于列表的组件（例如，List、DataGrid、TileList 或 ComboBox 组件）中的数据。
	 * 数据提供程序 是用作数据源的项目的线性集合，
	 * 例如，一个数组。数据提供程序中的每个项目都是包含一个或多个数据字段的对象或 XML 对象。
	 * 通过使用 DataProvider.getItemAt() 方法，可以按索引访问数据提供程序中包含的项目。
	 */
	public class DataProvider extends EventDispatcher
	{
        /**
         *数据
		 */
		protected var data:Array;


		/**
		 * 通过将列表、XML 实例或数据对象数组作为数据源，创建一个新的 DataProvider 对象。
		 */
		public function DataProvider(value:Object=null) 
		{			
			if (value == null)
			{
				data = [];
			} else
			{
				data = getDataFromObject(value);				
			}
		}

		/**
         * 数据提供程序包含的项目数。
		 */
		public function get length():uint 
		{
			return data.length;
		}

		/**
		 * 使指定索引处的项目失效。
		 */
		public function invalidateItemAt(index:int):void
		{
			checkIndex(index,data.length-1)
			dispatchChangeEvent(DataChangeType.INVALIDATE,[data[index]],index,index);
		}

		/**
		 * 使指定的项目失效。
		 */
		public function invalidateItem(item:Object):void
		{
			var index:uint = getItemIndex(item);
			if (index == -1) { return; }
			invalidateItemAt(index);
		}

		/**
         * 使 DataProvider 包含的所有数据项失效，并调度 DataChangeEvent.INVALIDATE_ALL 事件。
		 */
		public function invalidate():void 
		{
			dispatchEvent(new DataChangeEvent(DataChangeEvent.DATA_CHANGE, DataChangeType.INVALIDATE_ALL,data.concat(),0,data.length));
		}
		/**
		 * 将新项目添加到数据提供程序的指定索引处。
		 */
		public function addItemAt(item:Object,index:uint):void 
		{
			checkIndex(index,data.length);
			dispatchPreChangeEvent(DataChangeType.ADD,[item],index,index);
			data.splice(index,0,item);
			dispatchChangeEvent(DataChangeType.ADD,[item],index,index);
		}
		/**
		 * 将项目追加到数据提供程序的结尾。
		 */
		public function addItem(item:Object):void {
			dispatchPreChangeEvent(DataChangeType.ADD,[item],data.length-1,data.length-1);
			data.push(item);
			dispatchChangeEvent(DataChangeType.ADD,[item],data.length-1,data.length-1);
		}
		/**
		 * 向数据提供程序的指定索引处添加若干项目，并调度 DataChangeType.ADD 事件。
		 */
		public function addItemsAt(items:Object,index:uint):void
		{
			checkIndex(index,data.length);
			var arr:Array = getDataFromObject(items);
			dispatchPreChangeEvent(DataChangeType.ADD,arr,index,index+arr.length-1);			
			data.splice.apply(data, [index,0].concat(arr));
			dispatchChangeEvent(DataChangeType.ADD,arr,index,index+arr.length-1);
		}
		/**
		 * 向 DataProvider 的末尾追加多个项目，并调度 DataChangeType.ADD 事件。
		 */
		public function addItems(items:Object):void 
		{
			addItemsAt(items,data.length);
		}
		/**
		 * 将指定项目连接到当前数据提供程序的结尾。
		 */
		public function concat(items:Object):void 
		{
			addItems(items);
		}
		/**
		 *将指定数据追加到数据提供程序包含的数据，并删除任何重复的项目。
		 */
		public function merge(newData:Object):void 
		{
			var arr:Array = getDataFromObject(newData);
			var l:uint = arr.length;
			var startLength:uint = data.length;
			
			dispatchPreChangeEvent(DataChangeType.ADD,data.slice(startLength,data.length),startLength,this.data.length-1);
			
			for (var i:uint=0; i<l; i++)
			{
				var item:Object = arr[i];
				if (getItemIndex(item) == -1)
				{
					data.push(item);
				}
			}
			if (data.length > startLength) 
			{
				dispatchChangeEvent(DataChangeType.ADD,data.slice(startLength,data.length),startLength,this.data.length-1);
			} else 
			{
				dispatchChangeEvent(DataChangeType.ADD,[],-1,-1);
			}
		}

		/**
         *返回指定索引处的项目。
		 */
		public function getItemAt(index:uint):Object 
		{
			checkIndex(index,data.length-1);
			return data[index];
		}
		/**
         *返回指定项目的索引。
		 */
		public function getItemIndex(item:Object):int 
		{
			return data.indexOf(item);;
		}
		/**
		 * 删除指定索引处的项目，并调度 DataChangeType.REMOVE 事件。
		 */
		public function removeItemAt(index:uint):Object 
		{
			checkIndex(index,data.length-1);
			dispatchPreChangeEvent(DataChangeType.REMOVE, data.slice(index,index+1), index, index);
			var arr:Array = data.splice(index,1);
			dispatchChangeEvent(DataChangeType.REMOVE,arr,index,index);
			return arr[0];
		}
		/**
		 * 从数据提供程序中删除指定项目，并调度 DataChangeType.REMOVE 事件。
		 */
		public function removeItem(item:Object):Object 
		{
			var index:int = getItemIndex(item);
			if (index != -1)
			{
				return removeItemAt(index);
			}
			return null;
		}
		/**
		 * Removes all items from the data provider and dispatches a <code>DataChangeType.REMOVE_ALL</code>
         * event.
		 */
		public function removeAll():void 
		{
			var arr:Array = data.concat();
			
			dispatchPreChangeEvent(DataChangeType.REMOVE_ALL,arr,0,arr.length);
			data = [];
			dispatchChangeEvent(DataChangeType.REMOVE_ALL,arr,0,arr.length);
		}

		/**
		 * 从数据提供程序中删除所有项目，并调度 DataChangeType.REMOVE_ALL 事件。
		 */
		public function replaceItem(newItem:Object,oldItem:Object):Object
		{
			var index:int = getItemIndex(oldItem);
			if (index != -1)
			{
				return replaceItemAt(newItem,index);
			}
			return null;
		}
		/**
		 *  替换指定索引处的项目，并调度 DataChangeType.REPLACE 事件。
		 */
		public function replaceItemAt(newItem:Object,index:uint):Object 
		{
			checkIndex(index,data.length-1);
			var arr:Array = [data[index]];
			dispatchPreChangeEvent(DataChangeType.REPLACE,arr,index,index);
			data[index] = newItem;
			dispatchChangeEvent(DataChangeType.REPLACE,arr,index,index);
			return arr[0];
		}
		/**
		 * 对数据提供程序包含的项目进行排序，并调度 DataChangeType.SORT 事件。
		 */
		public function sort(...sortArgs:Array):* 
		{
			dispatchPreChangeEvent(DataChangeType.SORT,data.concat(),0,data.length-1);
			var returnValue:Array = data.sort.apply(data,sortArgs);
			dispatchChangeEvent(DataChangeType.SORT,data.concat(),0,data.length-1);
			return returnValue;
		}
		/**
		 * 按指定字段对数据提供程序包含的项目进行排序，并调度 DataChangeType.SORT 事件。
		 */
		public function sortOn(fieldName:Object,options:Object=null):* 
		{
			dispatchPreChangeEvent(DataChangeType.SORT,data.concat(),0,data.length-1);
			var returnValue:Array = data.sortOn(fieldName,options);
			dispatchChangeEvent(DataChangeType.SORT,data.concat(),0,data.length-1);
			return returnValue;
		}

		/**
		 * 创建当前 DataProvider 对象的副本。
		 */
		public function clone():DataProvider
		{
			return new DataProvider(data);
		}
		/**
		 * 创建数据提供程序包含的数据的 Array 对象表示形式。
		 */
		public function toArray():Array 
		{
			return data.concat();
		}
		/**
		 *创建数据提供程序包含的数据的字符串表示形式。
		 */
		override public function toString():String 
		{
			return "DataProvider ["+data.join(" , ")+"]";
		}
		/**
		 * 解析数据
		 */
		protected function getDataFromObject(obj:Object):Array
		{
			var retArr:Array;
			if (obj is Array) 
			{
				var arr:Array = obj as Array;
				if (arr.length > 0) 
				{
					if (arr[0] is String || arr[0] is Number) 
					{
						retArr = [];
						// convert to object array.
						for (var i:uint = 0; i < arr.length; i++)
						{
							var o:Object = {label:String(arr[i]),data:arr[i]}
							retArr.push(o);
						}
						return retArr;
					}
				}
				return obj.concat();
			} else if (obj is DataProvider)
			{
				return obj.toArray();
			} else if (obj is XML) 
			{
				var xml:XML = obj as XML;
				retArr = [];
				var nodes:XMLList = xml.*;
				for each (var node:XML in nodes) 
				{
					var obj:Object = {};
					var attrs:XMLList = node.attributes();
					for each (var attr:XML in attrs) 
					{
						obj[attr.localName()] = attr.toString();
					}
					var propNodes:XMLList = node.*;
					for each (var propNode:XML in propNodes)
					{
						if (propNode.hasSimpleContent()) 
						{
							obj[propNode.localName()] = propNode.toString();
						}
					}
					retArr.push(obj);
				}
				return retArr;
			} else
			{
				throw new TypeError("Error: Type Coercion failed: cannot convert "+obj+" to Array or DataProvider.");
				return null;
			}
		}
		
		/**
		 */
		protected function checkIndex(index:int,maximum:int):void 
		{
			if (index > maximum || index < 0) 
			{
				throw new RangeError("DataProvider index ("+index+") is not in acceptable range (0 - "+maximum+")");
			}
		}
		/**
		 */
		protected function dispatchChangeEvent(evtType:String,items:Array,startIndex:int,endIndex:int):void
		{
			dispatchEvent(new DataChangeEvent(DataChangeEvent.DATA_CHANGE,evtType,items,startIndex,endIndex));
		}
		/**
		 */
		protected function dispatchPreChangeEvent(evtType:String, items:Array, startIndex:int, endIndex:int):void
		{
			dispatchEvent(new DataChangeEvent(DataChangeEvent.PRE_DATA_CHANGE, evtType, items, startIndex, endIndex));
		}
	}

}